package com.example.myapplication;

/**
 * 单列模式  https://blog.csdn.net/xiaokang666/article/details/127470743
 * 3.双重检锁（Double Check Lock，DCL）
 *
 * （1）可以延迟加载；
 *
 * （2）线程安全的；
 *
 * （3）对JDK的版本有要求（1.5及以上）（需要使用volatile关键字来禁止指令重排的操作，这个在JDK1.5之后才出现）；
 */
public class Singleton {
	
	private volatile static Singleton instance;
	
	private Singleton() {}
	
	public static Singleton getInstance() {
		if(instance == null ) { 
			synchronized (Singleton.class) {
				if(instance == null) { 
					instance = new Singleton();
				}
			}
		}
		return instance;
	}
}

/**
 * 问题：为什么需要两次判断if(singleTon==null)?
 * 分析：第一次校验：由于单例模式只需要创建一次实例，如果后面再次调用getInstance方法时，则直接返回之前创建的实例，因此大部分时间不需要执行同步方法里面的代码，大大提高了性能。如果不加第一次校验的话，那跟上面的懒汉模式没什么区别，每次都要去竞争锁。
 *
 * 第二次校验：如果没有第二次校验，假设线程t1执行了第一次校验后，判断为null，这时t2也获取了CPU执行权，也执行了第一次校验，判断也为null。接下来t2获得锁，创建实例。这时t1又获得CPU执行权，由于之前已经进行了第一次校验，结果为null（不会再次判断），获得锁后，直接创建实例。结果就会导致创建多个实例。所以需要在同步代码里面进行第二次校验，如果实例为空，则进行创建
 *
 * 双检锁为什么要加上volatile关键字
 * uniqueInstance 采用 volatile 关键字修饰也是很有必要。
 *
 * uniqueInstance 采用 volatile 关键字修饰也是很有必要的， uniqueInstance = new Singleton(); 这段代码其实是分为三步执行：
 *
 * 1、为 uniqueInstance 分配内存空间
 * 2、初始化 uniqueInstance
 * 3、将 uniqueInstance 指向分配的内存地址
 *
 * 但是由于 JVM 具有指令重排的特性，执行顺序有可能变成 1->3->2。指令重排在单线程环境下不会出先问题，但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如，线程 T1 执行了 1 和 3，此时 T2 调用 getUniqueInstance() 后发现 uniqueInstance 不为空，因此返回 uniqueInstance，但此时 uniqueInstance 还未被初始化。
 *
 * 使用 volatile 可以禁止 JVM 的指令重排，保证在多线程环境下也能正常运行
 *
 * 为什么volatile可以一定程度上保证双检锁ok？
 * 1.volatile关键字可以保证jvm执行的一定的“有序性”，在指令1和指令2执行完之前，指定3一定不会被执行。
 * 为什么说是一定的"有序性"呢，因为对于非易失的读写，jvm仍然允许对volatile变量进行乱序读写
 *
 * 2.保证了volatile变量被修改后立刻刷新会驻内存中。
 *
 * 单例模式静态内部类为何线程安全
 * 静态内部类不会随着外部类的加载而加载 ,只有静态内部类的静态成员被调用时才会进行加载 , 这样既保证的惰性初始化（Lazy-Initialazation），又由JVM保证了多线程并发访问的正确性。
 *
 * 由于对象实例化是在内部类加载的时候构建的，因此该版是线程安全的(因为在方法中创建对象，才存在并发问题，静态内部类随着方法调用而被加载，只加载一次，不存在并发问题，所以是线程安全的)。
 *
 * 原理：外部类加载时，不一定加载内部类，内部类不加载则不会去初始化instance，故而不占用内存，只有当getInstance()方法第一次被调用时，才会去初始化instance，延迟了单例的实例化，也使得线程安全，代码如下
 * ————————————————
 * 版权声明：本文为CSDN博主「代码学习」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
 * 原文链接：https://blog.csdn.net/qq_42253147/article/details/93881038
 */